#pragma once

#include<iostream>
#include<sys/socket.h>
#include<functional>
#include<netinet/in.h>
#include<arpa/inet.h>

#include"ThreadPool.hpp"
#include"Lock.hpp"
#include"Log.hpp"
#include"InetAddr.hpp"

uint16_t default_port=8888;

using namespace LogMoudle;
using namespace LockModule;
using namespace InetAddrMoudle;
using namespace ThreadPoolMoudle;

using adduser_func=std::function<void(InetAddr&)>;



using task_func=std::function<void()>;
using route_func=std::function<void(int,const std::string)>;


class nocopy{
    public:
    nocopy(){}
    nocopy(const nocopy&)=delete;
    const nocopy& operator ==(const nocopy &)=delete;
    ~nocopy(){}
};



//服务器端
class UdpServer:public nocopy
{
    private:
    //服务器的端口和ip
    int _sockfd;
    InetAddr _addr;
    bool _isruning;

    //相应的操作方法类型

    adduser_func _adduer;
    task_func _task;
    route_func _route;

    public:

    //网络信息在这个地方初始化_addr时进行填充
    UdpServer(uint16_t port=default_port):_addr(port),_isruning(false)
    {

    }

    void InitServer()
    {
        //创建套接字，绑定相应的接口
        _sockfd=::socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd<0)
        {
            LOG(Logevel::INFO)<<"创建套接字失败.......";

            exit(1);
        }
        LOG(Logevel::INFO)<<"套接字创建成功.......";

        //填充网络信息
        int n=bind(_sockfd,_addr.GetAddr(),_addr.AddrLen());

        if(n<0)
        {
            LOG(Logevel::INFO)<<"绑定失败........";
            exit(1);
        }
        LOG(Logevel::INFO)<<"绑定成功........";

    }

    //将相应的函数对象实例化
    void Register_func(adduser_func adduser,route_func route)
    {
        _adduer=adduser;
        _route=route;
    }


    void Start()
    {
        _isruning=true;

        //服务器永不停歇
        while(true)
        {
            char buffer[1024];

            sockaddr_in peer;

            socklen_t len=sizeof(peer);

            ssize_t n=::recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,CONV(&peer),&len);

            if(n>0)
            {
                //表示从客户端收到了消息，该消息存到了buffer中
                //客户端发来的网络信息，存到了peer中
                InetAddr cline(peer);
                
                std::cout<<cline.PrintDebug()<<std::endl;

                buffer[n]=0;
                //这时我们需要调用线程池，将信息转发给其它用户
                
                std::string message;

                //添加相应的用户
                _adduer(cline);

                message=cline.Ip()+"# "+buffer;
                //发送相应的信息
                _task=std::bind(UdpServer::_route,_sockfd,message);
                ThreadPool<task_func>::GetInstance()->Enqueue(_task);
                
            }
        }
    }


};
